package com.pet_service.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import javax.swing.*;
import java.util.Collections;

/**
 * 权限认证框架的配置类
 */
@Configuration
@EnableWebSecurity
public class SecurityConfig {

    //不需要登录就能访问的接口
    private static final String[] PASSLIST = {"/login", "/logout", "/images/**", "/test/**",
            "/doc.html", "/webjars/**", "/v3/api-docs/**"};


    //登录成功处理器
    @Autowired
    private LoginSuccessHandler loginSuccessHandler;
    //登录失败处理器
    @Autowired
    private LoginFailureHandler loginFailureHandler;
    //用户详情服务(去数据user表查询用户,不使用默认的user账户)
    @Autowired
    private CustomUserDetailsService customUserDetailsService;
    //token认证失败处理器
    @Autowired
    private TokenAuthenticationEntryPoint tokenAuthenticationEntryPoint;
    @Autowired
    private CustomLogoutSuccessHandler customLogoutSuccessHandler;

   //tokenAuthenticationFilter是token认证过滤器,tokenAuthenticationEntryPoint是token认证失败处理器
    @Bean
    public TokenAuthenticationFilter tokenAuthenticationFilter(TokenAuthenticationEntryPoint tokenAuthenticationEntryPoint) {
        return new TokenAuthenticationFilter(tokenAuthenticationEntryPoint);
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        //DSL 指的是 Spring Security 提供的用于配置安全策略的流式 API。
        //这种链式调用和 Lambda 表达式的形式就是 Spring Security 的 DSL，它让安全配置变得更加直观和易于理解
        //开启跨域
        http.cors((cors)->{
                    cors.configurationSource(corsConfigurationSource());
                })
                //禁用csrf保护
                .csrf((csrf)->csrf.disable())
                //添加过滤器,在登录接口之前添加过滤器
                .addFilterBefore(tokenAuthenticationFilter(tokenAuthenticationEntryPoint), UsernamePasswordAuthenticationFilter.class)
                //设置会话创建策略为无状态
                .sessionManagement(session->
                        session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                //用户详情服务
                .userDetailsService(customUserDetailsService)
                //登录配置
                //.formLogin(form->{ ... })是 Spring Security 提供的一个 DSL 方法，用于配置基于表单的登录认证机制。
                .formLogin(form->{
                    //设置用户名参数,默认为username,密码参数为password
//                    .usernameParameter("username")
//                            .passwordParameter("password")
                    //登录成功后调用loginSuccessHandler处理器
                    form.usernameParameter("username")
                            .passwordParameter("password")
                            .successHandler(loginSuccessHandler)
                            .failureHandler(loginFailureHandler);
                })
                .exceptionHandling(exceptionHandling ->
                        exceptionHandling.authenticationEntryPoint(tokenAuthenticationEntryPoint))
                .logout(logout ->logout.logoutSuccessHandler(customLogoutSuccessHandler).clearAuthentication( true))
                //配置拦截规则
                .authorizeHttpRequests(authz -> authz
                        .requestMatchers(PASSLIST).permitAll() //设置放行路径
                        .anyRequest().authenticated() //其他接口需要登录认证
                );
        //构建并返回安全过滤器链
        return http.build();
    }


     //Spring Security 提供的 BCryptPasswordEncoder 来加密用户密码
     @Bean
     public PasswordEncoder passwordEncoder() {
         return new BCryptPasswordEncoder();
     }



    /**
     * 跨域配置
     */
    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.setAllowedHeaders(Collections.singletonList("*"));
        corsConfiguration.setAllowedMethods(Collections.singletonList("*"));
        corsConfiguration.setAllowedOrigins(Collections.singletonList("*"));
        corsConfiguration.setMaxAge(3600L);
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", corsConfiguration);
        return source;
    }
}
